热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

接龙|终点_动态规划:空间优化技巧以及接龙型动态规划

篇首语:本文由编程笔记#小编为大家整理,主要介绍了动态规划:空间优化技巧以及接龙型动态规划相关的知识,希望对你有一定的参考价值。 空间优化方法 滚动数组 如果状态依赖关系只在相邻的几层之间&#xf

篇首语:本文由编程笔记#小编为大家整理,主要介绍了动态规划:空间优化技巧以及接龙型动态规划相关的知识,希望对你有一定的参考价值。



空间优化方法


滚动数组



如果状态依赖关系只在相邻的几层之间,则可以使用滚动数组进行优化
滚动数组可以让空间复杂度降维



坐标型动态规划使用滚动数组

数字三角形的状态转移方程为
dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1]) + A[i][j]

滚动数组优化之后为
dp[i % 2][j] = min(dp[(i - 1) % 2][j], dp[(i - 1) % 2][j - 1]) + A[i][j]

因为每一步只与他的前一步有关,所以前面的数组我们可以重复使用,而不需要开辟新的空间。

随着滚动数组优化,我们需要改变的地方:

//原来的版本,详情请看动态规划入门:
public int minimumTotal(int[][] triangle)
if (triangle == null || triangle.length == 0)
return -1;

if (triangle[0] == null || triangle[0].length == 0)
return -1;


int n = triangle.length;
int[][] f = new int[n][n];

// initialize: 三角形的左边和右边要初始化
// 因为他们分别没有左上角和右上角的点
f[0][0] = triangle[0][0];
for (int i &#61; 1; i < n; i&#43;&#43;)
f[i][0] &#61; f[i - 1][0] &#43; triangle[i][0];
f[i][i] &#61; f[i - 1][i - 1] &#43; triangle[i][i];


// function: f[i][j] &#61; Math.min(f[i - 1][j], f[i - 1][j - 1]) &#43; triangle[i][j];
for (int i &#61; 1; i < n; i&#43;&#43;)
for (int j &#61; 1; j < i; j&#43;&#43;)
f[i][j] &#61; Math.min(f[i - 1][j], f[i - 1][j - 1]) &#43; triangle[i][j];


// answer: 最后一层的任意位置都可以是路径的终点
int best &#61; f[n - 1][0];
for (int i &#61; 1; i < n; i&#43;&#43;)
best &#61; Math.min(best, f[n - 1][i]);

return best;

//滚动数组版本&#xff1a;
public int minimumTotal(int[][] triangle)
if (triangle &#61;&#61; null || triangle.length &#61;&#61; 0)
return -1;

if (triangle[0] &#61;&#61; null || triangle[0].length &#61;&#61; 0)
return -1;


int n &#61; triangle.length;
//空间负责度进行了降纬 n &#61;> 2
int[][] f &#61; new int[2][n];

f[0][0] &#61; triangle[0][0];
// 因为数组空间不能够直接初始化&#xff0c;我们需要在动态的过程中初始化
for (int i &#61; 1; i < n; i&#43;&#43;)
f[i % 2][0] &#61; f[(i - 1) % 2][0] &#43; triangle[i][0];
f[i % 2][i] &#61; f[(i - 1) % 2][i - 1] &#43; triangle[i][i];
for (int j &#61; 1; j < i; j&#43;&#43;)
f[i % 2][j] &#61; min(f[(i - 1) % 2][j], f[(i - 1) % 2][j - 1]) &#43; triangle[i][j]


// answer: 最后一层的任意位置都可以是路径的终点
int best &#61; f[(i - 1) % 2][0];
for (int i &#61; 1; i < n; i&#43;&#43;)
best &#61; Math.min(best, f[(i - 1) % 2][i]);

return best;

从上面的不同的两个版本我们可以知道最大的区别在于初始化&#xff0c;因为数组空间不能够直接初始化&#xff0c;所以我们需要在动态的过程中初始化。

那么能否两个维度一起滚动呢?
dp[i][j] &#61; min(dp[i - 1][j], dp[i - 1][j - 1]) &#43; A[i][j] &#61;>
dp[i % 2][j % 2] &#61; min(dp[(i - 1) % 2][j % 2], dp[(i - 1) % 2][(j - 1) % 2]) &#43; A[i][j]



不可以&#xff0c;因为j不是全局单调递增的&#xff0c;所以他的数据需要被保存&#xff0c;而 i 是全局单调递增的。


所以我们可以得出&#xff0c;滚动数组只可以滚动一个维度&#xff0c;不能滚动两个维度。

实例&#xff1a;
斐波那契数列

class Solution
public int fib(int n)
int[] dp &#61; new int[3];
dp[0%3] &#61; 0;
dp[1%3] &#61; 1;
for(int i &#61; 2 ; i <&#61; n; i&#43;&#43;)
dp[i % 3] &#61; (dp[(i - 1) % 3] &#43; dp[(i - 2) % 3]) % 1000000007;


return dp[n%3];


总结&#xff1a;


  • 滚动数组滚动的是第一重循环的变量&#xff0c;而不是第二重甚至第三重
  • 滚动数组也只能滚一个维度
  • 不能两个维度一起滚动

接龙型动态规划



属于“坐标型”动态规划的一种 题型一般是告诉你一个接龙规则&#xff0c;让你找最长的龙


经典例题&#xff1a;
LeetCode 300. 最长递增子序列

给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

例子1:
输入&#xff1a;nums &#61; [10,9,2,5,3,7,101,18]
输出&#xff1a;4
解释&#xff1a;最长递增子序列是 [2,3,7,101]&#xff0c;因此长度为 4

利用动规四要素分析&#xff1a;

state:
dp[i] 表示以第 i 个数为龙尾的最长的龙有多长
function:
dp[i] &#61; maxdp[j] &#43; 1, j < i && nums[j] < nums[i]
initialization://每个位置都可以是龙头
dp[0..n-1] &#61; 1
answer:
maxdp[0..n-1]

Follow up: 求具体的方法

倒推法
记录每个状态的最优值是从哪个前继状态来的 通常需要一个和状态数组同样维度的数组 prev[i] 记录 使得 dp[i] 获得最优值的那个 j 是谁 j 是方程 dp[i] &#61; maxdp[j] &#43; 1 里的j

最长上升连续子序列 II
描述&#xff1a;
给定一个整数矩阵. 找出矩阵中的最长连续上升子序列, 返回它的长度. 最长连续上升子序列可以从任意位置开始, 向上/下/左/右移动.

输入:
[
[1, 2, 3, 4, 5],
[16,17,24,23,6],
[15,18,25,22,7],
[14,19,20,21,8],
[13,12,11,10,9]
]
输出: 25
解释: 1 -> 2 -> 3 -> 4 -> 5 -> ... -> 25 (由外向内螺旋)

LeetCode 368.最大整除子集

描述&#xff1a;

给出一个由无重复的正整数组成的集合&#xff0c;找出其中最大的整除子集&#xff0c;子集中任意一对 (Si&#xff0c;Sj) 都要满足&#xff1a;Si % Sj &#61; 0 或 Sj % Si &#61; 0。

如果有多个目标子集&#xff0c;返回其中任何一个均可。

示例 1:
输入: [1,2,3]
输出: [1,2] (当然, [1,3] 也正确)

class Solution
public List<Integer> largestDivisibleSubset(int[] nums)
if (nums &#61;&#61; null || nums.length &#61;&#61; 0)
return new ArrayList();


Arrays.sort(nums);
int n &#61; nums.length;
HashMap<Integer, Integer> dp &#61; new HashMap();
HashMap<Integer, Integer> prev &#61; new HashMap();

for (int i &#61; 0; i < n; i&#43;&#43;)
dp.put(nums[i], 1);
prev.put(nums[i], -1);


int lastNum &#61; nums[0];
for (int i &#61; 0; i < n; i&#43;&#43;)
int num &#61; nums[i];
for (Integer factor : getFactors(num))
if (!dp.containsKey(factor))
continue;

if (dp.get(num) < dp.get(factor) &#43; 1)
dp.put(num, dp.get(factor) &#43; 1);
prev.put(num, factor);


if (dp.get(num) > dp.get(lastNum))
lastNum &#61; num;



return getPath(prev, lastNum);


private List<Integer> getPath(HashMap<Integer, Integer> prev, int lastNum)
List<Integer> path &#61; new ArrayList();
while (lastNum !&#61; -1)
path.add(lastNum);
lastNum &#61; prev.get(lastNum);

Collections.reverse(path);
return path;


private List<Integer> getFactors(int num)
List<Integer> factors &#61; new ArrayList();
if (num &#61;&#61; 1)
return factors;

int factor &#61; 1;
while (factor * factor <&#61; num)
if (num % factor &#61;&#61; 0)
factors.add(factor);
if (factor !&#61; 1 && num / factor !&#61; factor)
factors.add(num / factor);


factor&#43;&#43;;

return factors;



推荐阅读
  • 转载请注明原文地址:http:www.cnblogs.comygj0930p6409067.html1:HammingdistanceTheHammin ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 基于halcon的特征匹配实例
    特征匹配原图模板识别图代码结果原图模板识别图代码*这个例子在图片数据库中查找文章的页面。*第一步是训练不同的页面并创建模型。*然后搜索未知图像并检测出正确的文章页面。*请注意& ... [详细]
  • 一.元祖类型 (tuple)1.什么是元祖?用途:用于存放多个值,当存放的多个值只有读的需求没有改变的需求时,用元祖最合适.定义方式:在()内用逗号分隔开的多个任意类型的值t(1, ... [详细]
  • 对于我当前的需求,我需要绘制一些我从mongodb中获取的数据的图表,并且我正在使用reactPo ... [详细]
  • 看过上回《厘清需求篇》,读者想到多少个解呢?本篇首先谈及一些基本分析,之后会按两种API设计(纯函数API和含状态的API), ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 我正在尝试使用 ... [详细]
  • 本文整理了Java中org.apache.commons.collections4.ListUtils.unmodifiableList()方法的一些代码示例,展示了 ... [详细]
  • CF809A:Do you want a date?(数学  思维)
    A.Doyouwantadate?timelimitpertest2secondsmemorylimitpertest256megabytesinputstandardinputo ... [详细]
author-avatar
国务二局
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有